#include "RecordPlayer.h"

#include <QFileInfo>

#include <fstream>
#include <chrono>

void RecordPlayer::thread_function()
{
    _state = shell::RunnerState::Running;
    emit ran_signal();

    std::ifstream is(_ran_path.toStdString());
    if (!is) {
        _state = shell::RunnerState::Stoped;
        emit stoped_signal();
        return;
    }

    std::string str;

    while(std::getline(is,str)) {
        if (_lets_stop)
            break;
            
        emit notification_received_signal(QString::fromStdString(str));

        if (str.substr(0,6) == "#Time:")
            std::this_thread::sleep_for(std::chrono::milliseconds(10));

        if (_lets_pause) {
            _state = shell::RunnerState::Paused;
            emit paused_signal();
            std::unique_lock<std::mutex> locker(_pause_mutex);
            _pause_condition.wait(locker, [this]{ return !_lets_pause || _lets_stop; });
            _state = shell::RunnerState::Running;
            emit ran_signal();
        }
    }

    _state = shell::RunnerState::Stoped;
    emit stoped_signal();
}

RecordPlayer::RecordPlayer(shell::Runner_plugin * plugin, shell::Access_interface & shell)
    : _plugin(plugin)
    , _shell(shell)
{
    _run_management = _shell.getRunnerManagement();

    connect(this, &RecordPlayer::notification_received_signal, this, &RecordPlayer::notification_received_slot);
    connect(this, &RecordPlayer::ran_signal, this, &RecordPlayer::ran_slot);
    connect(this, &RecordPlayer::paused_signal, this, &RecordPlayer::paused_slot);
    connect(this, &RecordPlayer::stoped_signal, this, &RecordPlayer::stoped_slot);
}

QString RecordPlayer::name() const
{
    return tr("Player");
}

QString RecordPlayer::description() const
{
    return tr("Modeling record player");
}

bool RecordPlayer::isRunnable(const QString & path) 
{
    return QFileInfo(path + SIMULATION_RECORD_EXTENTION).exists();
}

bool RecordPlayer::startModeling(const QString & path) 
{
    _error_text = "";

    if (_state == shell::RunnerState::Paused) {
        _lets_pause = false;
        _pause_condition.notify_one();
        return true;
    }

    if (!isRunnable(path)) {
        _error_text = tr("The simulation for file '%1' cannot be played").arg(path);
        return false;
    }

    if (_thread && _thread->joinable())
        _thread->join();

    _lets_stop = _lets_pause = false;
    _ran_path = path + SIMULATION_RECORD_EXTENTION;
    _thread = std::make_unique<std::thread>(&RecordPlayer::thread_function, this);

    return true;
}

bool RecordPlayer::pauseModeling() 
{
    if (_state == shell::RunnerState::Paused)
        return true;

    if (_thread && _state == shell::RunnerState::Running) {
        _lets_pause = true;
    }

    return true;
}

bool RecordPlayer::stopModeling() 
{
    if (_thread && _thread->joinable()) {
        _lets_stop = true;
        _lets_pause = false;
        _pause_condition.notify_one();
        _thread->join();
        _thread.reset();
    }

    return true;
}

void RecordPlayer::notification_received_slot(const QString text)
{
    if (_run_management)
        _run_management->received(text);
}

void RecordPlayer::ran_slot()
{
    if (_run_management)
        _run_management->started();
}

void RecordPlayer::paused_slot()
{
    if (_run_management)
        _run_management->paused();
}

void RecordPlayer::stoped_slot()
{
    if (_run_management)
        _run_management->stoped();
}

